package cn.xutongxue.gtms.utils.excel;

import cn.xutongxue.gtms.constant.UserConstant;
import cn.xutongxue.gtms.entity.User;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.IService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class StudentImportListener<T> implements ReadListener<T> {

    /**
     * 实体类队形的Service方法
     */
    private final IService<T> baseService;

    /**
     * 每隔3000条存储数据库，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 3000;

    /**
     * 缓存的数据
     */
    private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    /**
     * 统计
     */
    private final AtomicInteger count = new AtomicInteger(0);

    public StudentImportListener(IService<T> baseService) {
        this.baseService = baseService;
    }

    /**
     * 解析Excel数据，每解析一条执行一次
     * @param entity 解析的实体类对象
     * @param analysisContext
     */
    @Override
    public void invoke(T entity, AnalysisContext analysisContext) {
        count.addAndGet(1);
        log.info("解析到一条数据:{}", JSON.toJSONString(entity));
        ((User) entity).setAvatar(UserConstant.DEFAULT_AVATAR);
        ((User) entity).setPassword(UserConstant.DEFAULT_PASSWORD);
        ((User) entity).setState(0);
        ((User) entity).setIsDeleted(0);
        ((User) entity).setRole("student");
        cachedDataList.add(entity);
        // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
        if (cachedDataList.size() >= BATCH_COUNT) {
            batchInsert();
            // 存储完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    /**
     * 解析Excel的所有数据执行该方法
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        batchInsert();
        log.info("所有数据解析完成！");
    }

    /**
     * 数据入库
     */
    @Async
    public void batchInsert() {
        log.info("{}条数据，开始存储数据库!", count.get());
        baseService.saveBatch(cachedDataList);
        log.info("存储数据库成功!");
    }

}
